#include "bridge.h"
#include <QDebug>
#include <QFile>
#include <QTextCodec>

IBridge* getBridge()
{
	IBridge* p_bridge = new Bridge();
	return p_bridge;
}

Bridge::Bridge()
{
	_path="adb/adb.exe"; 
	_command.clear();
	_selectedDevice.clear();  
}

Bridge::~Bridge()
{
	killServer();
}

//read output data
void Bridge::readOutput(QProcess* process,QString* rData, QString* rError)
{
	rData->clear();
	rError->clear();
	// Continue reading the data until EOF reached
	while(process->waitForReadyRead())
	{
		rData->append(process->readAllStandardOutput());
		rError->append(process->readAllStandardError());
	}
}

//read output data
void Bridge::readOutputForThread(QProcess* process,QString* rData, QString* rError)
{
	rData->clear();
	rError->clear();
	// Continue reading the data until EOF reached
	while(process->waitForReadyRead(-1))
	{
		rData->append(process->readAllStandardOutput());
		rError->append(process->readAllStandardError());
	}
	process->waitForFinished(-1);
}

//start adb server
void Bridge::startServer()
{
	killServer();
	_command=_path+" start-server";
    _process.start(_command);
	readOutput(&_process,&_data,&_error);
}
	
//kill adb server
void Bridge::killServer()
{
	_command=_path+" kill-server";
    _process.start(_command);
	readOutput(&_process,&_data,&_error);
}

//return list of unparsed strings with adb-name and model of device
QString Bridge::getDevices()
{
	_command=_path+" devices";
    _process.start(_command);
	readOutput(&_process,&_data,&_error);
	return _data;
}

//method sets name of the selected device at the moment
void Bridge::setSelectedDevice(QString s)
{
	_selectedDevice=s;
}

//save screenshot to path
bool Bridge::getScreenshot(QString str)
{
	qDebug() << "filepath: "<<str;
	QProcess process;
	QString command=_path+" -s "+_selectedDevice+" shell screencap -p";
	process.start(command);
	
	QByteArray* image = new QByteArray();

	bool result=false;
	// Continue reading the data until EOF reached
	while(process.waitForReadyRead(-1))
	{
		image->append(process.readAllStandardOutput());
	}

	process.waitForFinished(-1);
	qDebug()<<"Size 1: "<<image->length();
	image->replace("\r\r\n", "\n");
	qDebug()<<"Size 2: "<<image->length();

	QFile outFile(str);
	if (!image->isEmpty()) 
	{
		if (!outFile.open(QIODevice::WriteOnly))
		{
			qDebug() << "Error opening a file\n";
		}
		else
		{
			outFile.write(*image);
			outFile.close();
			result=true;
		}
	}
	delete image;
	return result;
}

//return file system
QString Bridge::getFileSystem(QString s)
{
	_command=_path+" -s "+_selectedDevice+" shell ls -la \""+s+"\"";
	_process.start(formatToUTF8(_command));

	readOutput(&_process,&_data,&_error);
	return _data;
}


//method to create new Folder
bool Bridge::newFolder(QString name, QString path)
{
	_command = _path + " -s " + _selectedDevice + " shell mkdir \"" + path + name +"\"";
	_process.start(formatToUTF8(_command));

	readOutput(&_process,&_data,&_error);
	qDebug()<<"new_folder"<<_data;
	qDebug() <<"error:"<< _error;
	return _data.isEmpty()? true:false;
}

//method to remove selected item(folder,file)
bool Bridge::Delete(QString path, QString name)
{
	_command = _path + " -s " + _selectedDevice + " shell rm -r  \"" + path + name +"\"";
	_process.start(formatToUTF8(_command));
	readOutput(&_process,&_data,&_error);
	qDebug()<< "command "<< _command;
	qDebug()<<"delete_folder"<<_data;
	return _data.isEmpty()? true:false;
}




//method which provide installing .apk file from selected directory(PC or device)
bool Bridge::Install(QString cmd)
{
	QProcess *proc = new QProcess();
	QString command = _path + " -s " + _selectedDevice + cmd ;
	proc->start(formatToUTF8(command));
	QString data,error;
	readOutputForThread(proc,&data,&error);
	
	qDebug() <<"install"<< data;
	if(proc)
		delete proc;
	bool res=data.contains("Success");
	return res;
}

//copy file to device
bool Bridge::pushToDevice(QString filePath,QString devicePath)
{
	QProcess *proc = new QProcess();
	int index = filePath.lastIndexOf("/")+1;
	QString name = filePath.right(filePath.length()-index);
	qDebug()<<"name:"<<name;
	QStringList arguments;
	arguments<<"-s"<<_selectedDevice<<"push";
	arguments.append(filePath);
	QString temp = devicePath + name;
	arguments.append(formatToUTF8(temp));
	qDebug()<<arguments;
	
	proc->start(_path,arguments);
	QString data,error;
	readOutputForThread(proc,&data,&error);

	qDebug() <<"error:"<< error;
	bool res = error.contains("bytes in");
	if(proc)
		delete proc;
	return res;
}

//copy file from device
bool Bridge::pullFromDevice(QString filePathOnDevice,QString pullPath)
{
	QProcess *proc = new QProcess();
	pullPath.replace("/","\\");
	int index = filePathOnDevice.lastIndexOf("/")+1;
	QString name = filePathOnDevice.right(filePathOnDevice.length()-index);
	qDebug()<<"name:"<<name;

	QStringList arguments;
	arguments<<"-s"<<_selectedDevice<<"pull";
	arguments.append(formatToUTF8(filePathOnDevice));

	qDebug()<<pullPath;
	QString temp;
	if (pullPath.endsWith("\\")) 
		temp = pullPath + name;
	else
		temp = pullPath + "\\" + name;
	qDebug()<<temp;
	arguments.append(temp);
	qDebug()<<arguments;

	proc->start(_path,arguments);
	QString data,error;
	readOutputForThread(proc,&data,&error);

	qDebug() <<"error:"<< error;
	bool res = error.contains("bytes in");
	if(proc)
		delete proc;
	return res;	
}

//move or copy files and dirs
bool Bridge::moveFiles(QStringList sourcePath,QString destinationPath,bool isCopy)
{
	if (!sourcePath.isEmpty())
	{
		QString fileSystemPath = sourcePath.first();
		if (fileSystemPath != destinationPath)
		{	
			bool res = true;
			for (int i=1;i<sourcePath.count();i++)
			{
				QStringList arguments;
				arguments<<"-s"<<_selectedDevice<<"shell";

				if (isCopy)
					arguments<<"cp"<<"-R"<<"-f";//<<"-p";
				else
					arguments<<"mv";

				QString temp = fileSystemPath + sourcePath[i];
				arguments.append(formatToUTF8(temp));
				arguments.append(formatToUTF8(destinationPath));

				qDebug()<<arguments;
				_process.start(_path,arguments);
				readOutput(&_process,&_data,&_error);
				if (!_data.isEmpty()) res=false;
			}
			return res;
		}
	}
	return 0;
}

bool Bridge::makeBackup(QString str)
{
	QProcess* process = new QProcess();
	QString command = _path + " -s " + _selectedDevice + " backup " + str;
	
	process->start(formatToUTF8(command));
	
	QString data,error;
	readOutputForThread(process,&data,&error);
	qDebug()<<"make backup:"<<data;
	qDebug() <<"error:"<< error;
	
	if(process)
		delete process;
	return data.isEmpty()? false:true;
}

bool Bridge::restoreBackup(QString file)
{
	QProcess *proc = new QProcess();
	QString command = _path + " -s " + _selectedDevice + " restore \"" + file + "\"";
	proc->start(formatToUTF8(command));

	QString data,error;
	readOutputForThread(proc,&data,&error);
	if(proc)
		delete proc;
	return data.isEmpty()? false:true;
}

//This method providing to use UTF8 codec
QString Bridge::formatToUTF8(QString src)
{
	QTextCodec *codec = QTextCodec::codecForName("CP1251");
	QString final = codec->toUnicode(src.toUtf8());
	return final;
}

QString Bridge::getDevicesProps(QString device)
{
	_command = _path + " -s " + device + " shell getprop";
	_process.start(_command);
	readOutput(&_process,&_data,&_error);	
	return _data;
}

bool Bridge::Rename(QString str)
{
	_command = _path + " -s " + _selectedDevice + " shell mv "+str;	
	_process.start(formatToUTF8(_command));
	readOutput(&_process,&_data,&_error);	
	qDebug()<<"rename:"<<_data;
	qDebug() <<"error:"<< _error;
	return _data.isEmpty()? true:false;
}

